/*
 * ns3.c
 *
 *  Created on: 17 sept. 2013
 *      Author: the
 */
#include"ns3.h"

//Algorithm est une variable globale dans ns3.h (il faut supprimer la variable passe en argument ci-dessous).
int NS3file(int variantTopology, int nbOfRoutes, char* fileName)
{
	FILE* ptrFile;
	int nbOfComputedRoutes;

	//Simulation de l'allocation
	initArrayNodes(variantTopology);


	//We compute nbOfRadios different path to the destination
	nbOfComputedRoutes=0;
	while( (nbOfComputedRoutes<nbOfRoutes) && (updateRouteSourceDestination(0, nbOfNodes-1, nbOfComputedRoutes)>=0) )
	{
		nbOfComputedRoutes++;
	}

	//There is no route to the destination - we return.
	if(nbOfComputedRoutes==0) return(0);


	switch(algorithm){
		case 0: allocateSameFrequency(nbOfComputedRoutes);
			break;
		case 1:	allocateFrequencyGreedy(nbOfComputedRoutes);
			break;
		case 2: allocateFrequencyTabu();
			break;
		case 3: allocateFrequencyMcair();
			break;
		case 4: allocateFrequencyAnh(nbOfComputedRoutes);
			break;
		default:
			fprintf(stderr,"Bad value of Algorithm (must be in [1-4]\n");
			exit(2);
	}

	//DEBUG
//	allocateSameFrequency(nbOfComputedRoutes);
//	conflictGraphLink2(7, 8, 1);
//	conflictGraphLink2(3,2,0);



	//L'allocation est faite, les tables de routage a jour. On commence ici la generation du fichier ns3.
	//Ouverture du fichier.
	ptrFile=fopen(fileName,"w+");
	if(ptrFile==NULL){
		perror("Erreur ouverture fichier");
		exit(1);
	}

	NS3header(ptrFile);
	NS3genereNoeuds(ptrFile);
	NS3defineMAC(ptrFile);//C'est ici qu'il faut changer le type de couche MAC
	NS3definePhyChannel(ptrFile);
	NS3interfacesAdresses(ptrFile,nbOfComputedRoutes);
	NS3nodesLocation(ptrFile);
	NS3staticRouting(ptrFile);
	NS3application(ptrFile, 0, nbOfNodes-1, nbOfComputedRoutes); //0--> Source - nbOfNodes-1 --> destination
	NS3simule(ptrFile);
	NS3footer(ptrFile);

	//A commenter si on n'aime pas l'art
	dessineGraph();


	//Fermeture du fichier
	fclose(ptrFile);

	return(1);
}

void NS3header(FILE* ptrFile)
{
	//Les includes<>
	fprintf(ptrFile,"/* Fichier genere automatiquement par le simulateur d'allocation de Frequence */\n");
	fprintf(ptrFile,"/* Anthony Busson - Universite Paris Sud 11 \t\t\t\t */\n");
	fprintf(ptrFile,"#include \"ns3/core-module.h\"\n");
	fprintf(ptrFile,"#include \"ns3/mobility-module.h\"\n");
	fprintf(ptrFile,"#include \"ns3/yans-wifi-helper.h\"\n");
	fprintf(ptrFile,"#include \"ns3/nqos-wifi-mac-helper.h\"\n");
	fprintf(ptrFile,"#include \"ns3/network-module.h\"\n");
	fprintf(ptrFile,"#include \"ns3/internet-module.h\"\n");
	fprintf(ptrFile,"#include \"ns3/point-to-point-module.h\"\n");
	fprintf(ptrFile,"#include \"ns3/applications-module.h\"\n");
	fprintf(ptrFile,"#include \"fstream\"\n\n\n");


	fprintf(ptrFile,"using namespace ns3;\n\n");
	fprintf(ptrFile,"NS_LOG_COMPONENT_DEFINE (\"ALGO_ALLOC\");\n\n");

	fprintf(ptrFile," int\nmain(int argc, char *argv[])\n{\n");
	fprintf(ptrFile,"\tLogComponentEnable(\"UdpClient\", LOG_LEVEL_INFO);\n");
	fprintf(ptrFile,"\tLogComponentEnable(\"UdpServer\", LOG_LEVEL_INFO);\n\n");


}

void NS3genereNoeuds(FILE* ptrFile)
{
	fprintf(ptrFile,"\tNodeContainer nodes;\n");
	fprintf(ptrFile,"\tnodes.Create(%d);\n\n",nbOfNodes);
}

void NS3defineMAC(FILE* ptrFile)
{
	fprintf(ptrFile,"\tNqosWifiMacHelper wifiMac = NqosWifiMacHelper::Default();\n");
	fprintf(ptrFile,"\twifiMac.SetType (\"ns3::AdhocWifiMac\");\n\n");
}

void NS3definePhyChannel(FILE* ptrFile)
{
	int i;

	//Une couche Phy par frequence.
	for(i=1;i<=maxFreq;i++)
		fprintf(ptrFile,"\tYansWifiPhyHelper wifiPhy%d = YansWifiPhyHelper::Default();\n",i);
	if(ns3Version==1){
		for(i=1;i<=maxFreq;i++)
			fprintf(ptrFile,"\twifiPhy%d.SetChannelId(%d);//Channel %d\n",i,i,i);
	}else{
		for(i=1;i<=maxFreq;i++)
			fprintf(ptrFile,"\twifiPhy%d.SetChannel(\"%d\");//Channel %d\n",i,i,i);
	}

	//Creation du channel et association a la couche Phy
	fprintf(ptrFile,"\tYansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default();\n");
	for(i=1;i<=maxFreq;i++)
		fprintf(ptrFile,"\twifiPhy%d.SetChannel(wifiChannel.Create());\n",i);
	fprintf(ptrFile,"\n");

	fprintf(ptrFile,"\tWifiHelper wifi = WifiHelper::Default();\n");
	fprintf(ptrFile,"\twifi.SetRemoteStationManager (\"ns3::IdealWifiManager\");\n\n");

	fprintf(ptrFile,"\tInternetStackHelper stack;\n");
	fprintf(ptrFile,"\tstack.Install (nodes);\n\n");
}

void NS3interfacesAdresses(FILE* ptrFile, int nbOfRoutes)
{
	int i, j;

	if(nbOfNodes>255) fprintf(stderr,"Erreur: le nombre de noeuds ne peut depasser 255\n");
	if(nbOfNodes>255) fprintf(stderr,"  il faut changer le systeme d'allocation des adresses.\n");
	if(nbOfRadios>MAX_FREQ)
	{
		fprintf(stderr,"Erreur: le nombre de radios (%d) ne peut etre superieure a la contsante MAX_FREQ (%d)\n",nbOfRadios,MAX_FREQ);
		exit(2);
	}

	fprintf(ptrFile,"\t//Creation des interfaces et des adresses\n");
	fprintf(ptrFile,"\tNetDeviceContainer devices;\n");
	fprintf(ptrFile,"\tIpv4InterfaceContainer interfaces;\n");

	//1 poule d'adresses pour chaque radio
	for(i=1;i<=nbOfRadios;i++)
		fprintf(ptrFile,"\tIpv4AddressHelper address%d;//address radio %d\n",i,i);

	for(i=1;i<=nbOfRadios;i++)
		fprintf(ptrFile,"\taddress%d.SetBase (\"10.%d.0.0\",\"255.255.255.0\");\n",i,i);
	fprintf(ptrFile,"\n\n");

	//Allocation des frequences et des adresses IP aux interfaces
	for(i=0;i<nbOfNodes-1;i++)
	{
		fprintf(ptrFile,"\t//Node %d \n",i);

		//On alloue une adresse IP a toutes les interfaces independemment du nombre de freq alloue.
		//On assigne aux interfaces non alloue la frequence1 (a modifier si necessaire).
		for(j=0;j<nbOfRadios;j++){
			//Il y a un decalage de 1 ente les freqs de NS (1, 2, 3, etc) et celle de ce logiciel (0, 1 , 2, etc.)
			if(nodes[i].frequency[j]!=-1)
				fprintf(ptrFile,"\tdevices = wifi.Install(wifiPhy%d,wifiMac, nodes.Get(%d));\n",nodes[i].frequency[j]+1,i);
			else fprintf(ptrFile,"\tdevices = wifi.Install(wifiPhy1,wifiMac, nodes.Get(%d));\n",i);

			fprintf(ptrFile,"\t //TheAnh-pass1 \n");
			fprintf(ptrFile,"\tinterfaces = address%d.Assign(devices);\n",j+1);
		}//fin du for sur j
	}//fin du for sur i

	//Allocation des frequences et des adresses IP aux interfaces de la destination
	//C'est un cas particulier car pour lui on alloue autant de cartes que de routes. Cela permet d'avoir autant d'adresses IP que de routes.
	fprintf(ptrFile,"\t//Node %d \n",i);

	//On alloue une adresse IP a toutes les interfaces independemment du nombre de freq alloue.
	//On assigne aux interfaces non alloue la frequence1 (a modifier si necessaire).
	//La destination est le noeud nbOfnodes-1
	for(j=0;j<nbOfRoutes;j++){
		//Il y a un decalage de 1 ente les freqs de NS (1, 2, 3, etc) et celle de ce logiciel (0, 1 , 2, etc.)
		if(nodes[nbOfNodes-1].frequency[j]!=-1)
			fprintf(ptrFile,"\tdevices = wifi.Install(wifiPhy%d,wifiMac, nodes.Get(%d));\n",nodes[i].frequency[j]+1,i);
		else fprintf(ptrFile,"\tdevices = wifi.Install(wifiPhy1,wifiMac, nodes.Get(%d));\n",i);

		fprintf(ptrFile,"\t //TheAnh-pass2 \n");
		fprintf(ptrFile,"\tinterfaces = address%d.Assign(devices);\n",j+1);
	}//fin du for sur j

	fprintf(ptrFile,"\n\n");
}

void NS3nodesLocation(FILE* ptrFile)
{
	int i;

	fprintf(ptrFile,"\t//Position des noeuds\n");
	fprintf(ptrFile,"\tMobilityHelper mobility;\n");
	fprintf(ptrFile,"\tPtr<ListPositionAllocator> positionAlloc = CreateObject<ListPositionAllocator> ();\n");
	for(i=0;i<nbOfNodes;i++)
		fprintf(ptrFile,"\tpositionAlloc->Add (Vector(%.1f,%.1f,0.0));\n",nodes[i].x,nodes[i].y);
	fprintf(ptrFile,"\tmobility.SetPositionAllocator(positionAlloc);\n");
	fprintf(ptrFile,"\tmobility.SetMobilityModel(\"ns3::ConstantPositionMobilityModel\");\n");
	fprintf(ptrFile,"\tmobility.Install(nodes);\n\n");

	fprintf(ptrFile,"\n\n");
}

void NS3staticRouting(FILE* ptrFile)
{
	int i,j,destination,nextHop,radioSrc,radioNh;

	//Pointeurs sur les interfaces IPv4
	fprintf(ptrFile,"\t//Pointeurs sur les interfaces IPv4\n");
	for(i=0;i<nbOfNodes;i++) fprintf(ptrFile,"\tPtr<Ipv4> ipv4%d = nodes.Get(%d)->GetObject<Ipv4> ();\n",i,i);

	//Les routes statiques
	fprintf(ptrFile,"\t//Les routes statiques\n");
	fprintf(ptrFile,"\tIpv4StaticRoutingHelper ipv4RoutingHelper;\n");
	fprintf(ptrFile,"\tPtr<Ipv4StaticRouting> staticRouting;\n");

	//On parcours les noeuds (for sur i), puis les nbOfNodes entrees de la table de routage du noeud i (for sur j)
	for(i=0;i<nbOfNodes;i++)
	{
		fprintf(ptrFile,"\n\t//Node %d\n",i);
		fprintf(ptrFile,"\tstaticRouting = ipv4RoutingHelper.GetStaticRouting (ipv4%d);\n",i);

		for(j=0;j<nbOfNodes;j++){

			destination=nodes[i].routingTable[j].destination;
			if(destination>=0){
				//On recherche l'interface du Next Hop (necessaire pour l'adresse IP)
				//Le nextHop pour cette destination est
				nextHop=nodes[i].routingTable[j].nextHop;

				//On recherche la radio au niveau du noeud i et nextHop
				radioSrc=getRadioN1(nodes[i], nextHop);
				radioNh=getRadioN1(nodes[nextHop], i);

				//Error - Should not happen
				if((radioNh<0) || (radioNh<0)) {
					fprintf(stderr,"Error ns3.c staticRouting(): radioSrc=%d radioNh=%d - Node %d - Table Entry %d - destination=%d - nextHop %d\n",radioSrc,radioNh,i,j,destination,nextHop);
					exit(2);	
				}

				//La route numero "j" correspond a la jeme route que l'on a calcule - qui sera donc envoye sur la jieme carte de la destination
				fprintf(ptrFile,"\tstaticRouting->AddHostRouteTo (Ipv4Address(");
				fprintf(ptrFile,"\"10.%d.0.%d\"),Ipv4Address(",j+1,destination+1);
				fprintf(ptrFile,"\"10.%d.0.%d\"),%d);\n",radioNh+1,nextHop+1,radioSrc+1);

			}//fin du if(destination>=0)
		}//fin du for sur j
	}//fin du for sur i

	fprintf(ptrFile,"\n\n");

}

void NS3application(FILE* ptrFile, int source, int dest, int nbOfRoutes)
{
	int i;
	double delai;

	if(nbOfNodes<2) return;

	//Config du serveur
	//The UDP server

	fprintf(ptrFile,"\t uint16_t port = 4000; // Set port.\n");

	fprintf(ptrFile,"\t// Set the udpServer applications on all nodes.\n");
  	fprintf(ptrFile,"\tUdpServerHelper server (port);\n");//Port 4000
  	fprintf(ptrFile,"\tApplicationContainer apps = server.Install (nodes);\n");

  	fprintf(ptrFile,"\tapps.Start (Seconds (1.0));\n");
  	fprintf(ptrFile,"\tapps.Stop (Seconds (16.0));\n\n");

	//Warning: the number of routes <= number of interfaces
	for(i=0;i<nbOfRoutes;i++)
	{

		if(nodes[0].routingTable[i].cost2 > 0)
		{
			//Le debit est calcule sur la base du min_{sur le chemin} Bi/IE(i). Cette valeur se trouve dans le champ cost2 de la table de routage des noeuds.
			delai=0.001024*8/(1.3 * nodes[0].routingTable[i].cost2); // sans ameliorer
			fprintf(stderr,"--debug-- route %d cost=%d cost2=%f delai=%f\n",i,nodes[0].routingTable[i].cost,nodes[0].routingTable[i].cost2,delai);

			fprintf(ptrFile,"\t//Config du client - autant de clients que de routes (le client est la source)\n");
			fprintf(ptrFile,"\tUdpClientHelper client%d (Ipv4Address(\"10.%d.0.%d\"), port);//addr dest + no port\n",i+1,i+1,dest+1);
			fprintf(ptrFile,"\tclient%d.SetAttribute (\"MaxPackets\", UintegerValue (400000));\n",i+1);//Maximum number of packets

			fprintf(ptrFile,"\tclient%d.SetAttribute (\"Interval\", TimeValue(Seconds(%f)));\n",i+1,delai);
			fprintf(ptrFile,"\tclient%d.SetAttribute (\"PacketSize\", UintegerValue (1024));\n",i+1);//Packet size

			fprintf(ptrFile,"\tapps = client%d.Install (nodes.Get (0));// source noeud 0\n",i+1);
			fprintf(ptrFile,"\tapps.Start (Seconds (1.0%d));\n",i+1);//Si les clients demarrent au meme moment ca plante
			fprintf(ptrFile,"\tapps.Stop (Seconds (16.0));\n\n");
		}
	}
}

void NS3simule(FILE* ptrFile)
{
	fprintf(ptrFile,"\tSimulator::Run();\n");
	fprintf(ptrFile,"\tSimulator::Destroy();\n\n");
}

void NS3footer(FILE* ptrFile)
{
	fprintf(ptrFile,"\n\treturn 0;\n}\n");
}

//end of file

